﻿using MediaAutomatorLib.Configurations;
using MediaAutomatorLib.MediaOrganizer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MediaAutomatorLib.MediaFinder
{
    public class MediaTypeFinder
    {
        private Dictionary<MediaType, Regex> _recognizers;
        private Dictionary<MediaType, Regex> _ignorers;
      
        public MediaTypeFinder(IRecognizerConfiguration configuration)
        {
            LoadRecognizers(configuration);
        }

        private void LoadRecognizers(IRecognizerConfiguration configuration)
        {
            StringBuilder sb = new StringBuilder();
            _recognizers = new Dictionary<MediaType, Regex>();
            _ignorers = new Dictionary<MediaType, Regex>();
            
            foreach(string r in configuration.MoviesRecognizers)
                sb.Append("(").Append(r).Append(")|");
            sb.Length -= 1;
            _recognizers.Add(MediaType.Movie, new Regex(sb.ToString(), RegexOptions.IgnoreCase));

            sb.Clear();
            foreach (string r in configuration.TvShowsRecognizers)
                sb.Append("(").Append(r).Append(")|");
            sb.Length -= 1;
            _recognizers.Add(MediaType.TvShow, new Regex(sb.ToString(), RegexOptions.IgnoreCase));

            sb.Clear();
            foreach (string r in configuration.MoviesIgnorers)
                sb.Append("(").Append(r).Append(")|");
            sb.Length -= 1;
            _ignorers.Add(MediaType.Movie, new Regex(sb.ToString(), RegexOptions.IgnoreCase));

            sb.Clear();
            foreach (string r in configuration.TvShowsIgnorers)
                sb.Append("(").Append(r).Append(")|");
            sb.Length -= 1;
            _ignorers.Add(MediaType.TvShow, new Regex(sb.ToString(), RegexOptions.IgnoreCase));

        }

        public List<DirectoryNode> FindMediaNodes(DirectoryNode sourceNode, MediaType type)
        {
            var nodes = new List<MediaNode>();
            RecursiveFindMediaNodes(sourceNode.Path, nodes, type);
            return FilterNodesToMove(sourceNode, nodes);
        }

        private void RecursiveFindMediaNodes(String path, List<MediaNode> mediaNodes, MediaType type)
        {
            foreach (var directoryPath in Directory.GetDirectories(path))
                RecursiveFindMediaNodes(directoryPath, mediaNodes, type);

            foreach (var filePath in Directory.GetFiles(path))
            {
                Regex typeIgnorer = _ignorers[type];
                if (typeIgnorer.IsMatch(filePath))
                    continue;

                Regex typeRegex = _recognizers[type];
                if (typeRegex.IsMatch(filePath))
                    mediaNodes.Add(new MediaNode() { Type = type, Path = filePath} );                
            }
        }

        private DirectoryNode GetParent(string path)
        {
            int lastIndex = path.LastIndexOf("\\");
            string parentPath = path.Substring(0, lastIndex);
            return new DirectoryNode() {Path = parentPath};
        }

        private List<DirectoryNode> FilterNodesToMove(DirectoryNode topNode, IEnumerable<DirectoryNode> mediaNodes)
        {
            var nodesToMove = new List<DirectoryNode>();

            var nodes = mediaNodes.ToList();
            while (nodes.Count > 0)
            {
                var mediaNode = nodes[0];

                // If media is in download folder
                DirectoryNode parent = GetParent(mediaNode.Path);
                if (parent.Equals(topNode))
                {
                    nodesToMove.Add(mediaNode);
                }

                // If media is in some folder
                else
                {
                    var parentAux = GetParent(parent.Path);
                    while (!parentAux.Equals(topNode))
                    {
                        parent = parentAux;
                        parentAux = GetParent(parentAux.Path);
                    }

                    if (!nodesToMove.Contains(parent))
                    {
                        if (nodesToMove.Count(n => n.Path.Equals(parent.Path)) == 0)
                        {
                            nodesToMove.Add(parent);
                        }
                    }
                }


                nodes.Remove(mediaNode);
            }

            return nodesToMove;
        }


    }

}
